package com.bobo.web.provider.util.commutils;

/**
 * Created by linxiaofeng1 on 2016/8/29.
 */

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.util.HashMap;
import java.util.Map;

/**
 * Created with IntelliJ IDEA. User: Howie Hao Date: 14-7-7 Time: 下午1:55
 */
public class HttpRequestUtils {
    private static final Logger LOG = LoggerFactory.getLogger(HttpRequestUtils.class);
    private static final int DEFALUT_READ_TIMEOUT = 1000;
    private static final RestTemplatePools pools = RestTemplatePools.Impl.getInstance();

    /**
     * @param url
     * @return
     */
    public static String doGet(String url) {
        return doGet(url, null, DEFALUT_READ_TIMEOUT, String.class);
    }

    public static <T> T doGet(String url, Map<String, String> params, Class<T> tClass) {
        return doGet(url, params, DEFALUT_READ_TIMEOUT, tClass);
    }

    public static String doPost(String url, Map<String, String> params) {
        return doPost(url, params, DEFALUT_READ_TIMEOUT, String.class);
    }

    public static <T> T doPost(String url, Map<String, String> params, Class<T> tClass) {
        return doPost(url, params, DEFALUT_READ_TIMEOUT, tClass);
    }

    /**
     * @param params  params are used to expand the url.
     * @param timeout unit millisecond
     */
    public static <T> T doGet(String url, Map<String, String> params, int timeout, Class<T> tClass) {
        long startTime = System.currentTimeMillis();
        if (null == params) {
            params = new HashMap<>();
        }
        try {
            return pools.make(timeout).getForObject(url, tClass, params);
        } catch (Exception e) {
            LOG.error("error when request {}, {}", url, params, e);
        } finally {
            LOG.info("Http get request: {}, takes : {}ms", url, System.currentTimeMillis() - startTime);
        }
        return null;
    }

    /**
     * @param params  params are used to expand the url.
     * @param timeout unit millisecond
     */
    public static <T> T doGet(String url, Map<String, String> params, int timeout, Class<T> tClass, Map<String, String> headers) {
        long startTime = System.currentTimeMillis();
        try {
            HttpEntity<MultiValueMap<String, String>> httpEntity = null;
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
            if (headers != null) {
                for (String key : headers.keySet()) {
                    httpHeaders.add(key, headers.get(key));
                }
            }
            MultiValueMap<String, String> variables = new LinkedMultiValueMap<>();
            if (null != params) {
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    variables.add(entry.getKey(), entry.getValue());
                }
            }
            httpEntity = new HttpEntity<>(variables, httpHeaders);
            ResponseEntity<T> responseEntity = pools.make(timeout).exchange(url, HttpMethod.GET, httpEntity, tClass);
            if (null != responseEntity) {
                return responseEntity.getBody();
            }
        } catch (Exception e) {
            LOG.error("error when request {}, {}", url, params, e);
            LOG.warn("[MONIT] [{'name':'httpRequestException','type':'frequency'}] [MONIT]");
        } finally {
            LOG.info("Http post request: {}, form data: {}, takes : {}ms", url, params, System.currentTimeMillis() - startTime);
        }
        return null;
    }

    /**
     * @param params  params are used as the form data, not to expand the url.
     * @param timeout unit millisecond
     */
    public static <T> T doPost(String url, Map<String, String> params, int timeout, Class<T> tClass) {
        long startTime = System.currentTimeMillis();
        try {
            HttpEntity<MultiValueMap<String, String>> httpEntity = null;
            if (null != params) {
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
                MultiValueMap<String, String> variables = new LinkedMultiValueMap<>();
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    variables.add(entry.getKey(), entry.getValue());
                }
                httpEntity = new HttpEntity<>(variables, httpHeaders);
            }
            ResponseEntity<T> responseEntity = pools.make(timeout).exchange(url, HttpMethod.POST, httpEntity, tClass);
            if (null != responseEntity) {
                return responseEntity.getBody();
            }
        } catch (Exception e) {
            LOG.error("error when request {}, {}", url, params, e);
            LOG.warn("[MONIT] [{'name':'httpRequestException','type':'frequency'}] [MONIT]");
        } finally {
            LOG.info("Http post request: {}, form data: {}, takes : {}ms", url, params, System.currentTimeMillis() - startTime);
        }
        return null;
    }


    public static <T> T doPost(String url, Map<String, String> params, int timeout, Class<T> tClass, Map<String, String> headers) {
        long startTime = System.currentTimeMillis();
        try {
            HttpEntity<MultiValueMap<String, String>> httpEntity = null;
            if (null != params) {
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
                if (headers != null) {
                    for (String key : headers.keySet()) {
                        httpHeaders.add(key, headers.get(key));
                    }
                }
                MultiValueMap<String, String> variables = new LinkedMultiValueMap<>();
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    variables.add(entry.getKey(), entry.getValue());
                }
                httpEntity = new HttpEntity<>(variables, httpHeaders);
            }
            ResponseEntity<T> responseEntity = pools.make(timeout).exchange(url, HttpMethod.POST, httpEntity, tClass);
            if (null != responseEntity) {
                return responseEntity.getBody();
            }
        } catch (Exception e) {
            LOG.error("error when request {}, {}", url, params, e);
            LOG.warn("[MONIT] [{'name':'httpRequestException','type':'frequency'}] [MONIT]");
        } finally {
            LOG.info("Http post request: {}, form data: {}, takes : {}ms", url, params, System.currentTimeMillis() - startTime);
        }
        return null;
    }

    /**
     * post json data request
     *
     * @param params  params are used to expand the url.
     * @param timeout unit millisecond
     */
    public static <T> T doPostJson(String url, Map<String, Object> params, int timeout, Class<T> tClass, Map<String, String> headers) {
        long startTime = System.currentTimeMillis();
        try {
            HttpEntity httpEntity = null;
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.set("Content-Type", "application/json;charset=utf-8");
            if (headers != null) {
                for (String key : headers.keySet()) {
                    httpHeaders.add(key, headers.get(key));
                }
            }

            httpEntity = new HttpEntity(requestBody(params), httpHeaders);
            ResponseEntity<T> responseEntity = pools.make(timeout).exchange(url, HttpMethod.POST, httpEntity, tClass);
            if (null != responseEntity) {
                return responseEntity.getBody();
            }
        } catch (Exception e) {
            LOG.error("error when request {}, {}", url, params, e);
            LOG.warn("[MONIT] [{'name':'httpRequestException','type':'frequency'}] [MONIT]");
        } finally {
            LOG.info("Http post request: {}, form data: {}, takes : {}ms", url, params, System.currentTimeMillis() - startTime);
        }
        return null;
    }

    private static String requestBody(Object object) {
        try {
            return new ObjectMapper().writeValueAsString(object);
        } catch (JsonProcessingException e) {
            return "";
        }
    }

}

